﻿using System;
using System.Web;
using System.Windows.Forms;
using System.Collections.Generic;
using System.IO;
using System.Xml;


namespace teavch.Util.Web.UI.Automation
{

	public class AutomaticWebRequest
	{
		public string WuiaXmlFile { get; set; }
		public WebBrowser WebBrowser { get; set; }
		private AutomationElements _automationElements = null;
		public AutomationCases AutomationCases { get; set; }
		public bool RequestCompleted { get; set; }
		public bool NotifyAllEvent { get; set; }

		public event AutomaticWebRequestReadyForExecution AutomaticWebRequestReadyForExecution;
		public event AutomaticWebRequestReadyForNextStep AutomaticWebRequestReadyForNextStep;
		public event AutomaticWebRequestCompleted AutomaticWebRequestCompleted;

		public event AutomaticWebRequestStepCompleted AutomaticWebRequestStepCompleted;
		public event AutomaticWebRequestCaseCompleted AutomaticWebRequestCaseCompleted;

		private WebBrowserDocumentCompletedEventArgs _e = null;

		private int _currentCase = 0;
		private int _currentStep = 0;
		private int _currentElement = 0;
		private string _url = "";


		public AutomaticWebRequest( string _wuiaXmlFile )
		{

			this.WuiaXmlFile = _wuiaXmlFile;

			if ( !File.Exists( this.WuiaXmlFile ) )
			{
				throw new FileNotFoundException();
			}

			this.SetAutomationElement();

			if ( this.AutomationCases != null && this.AutomationCases.Count > 0 && this.AutomationCases[ 0 ].AutomationSteps != null && this.AutomationCases[ 0 ].AutomationSteps.Count > 0
				&& this.AutomationCases[ 0 ].AutomationSteps[ 0 ].AutomationElements != null && this.AutomationCases[ 0 ].AutomationSteps[ 0 ].AutomationElements.Count > 0 )
			{
				this.WebBrowser = new WebBrowser();
				this.WebBrowser.DocumentCompleted += WebBrowser_DocumentCompleted;
			}
			else
			{
				throw new InvalidProgramException( "Invalid program situation. Either of case/step/element is null or empty." );
			}
		}

		public AutomaticWebRequest( string _wuiaXmlFile, bool _notifyAllEvent )
			: this( _wuiaXmlFile )
		{
			this.NotifyAllEvent = _notifyAllEvent;
		}

		private void WebBrowser_DocumentCompleted( object sender, WebBrowserDocumentCompletedEventArgs e )
		{
			if ( this.WebBrowser.DocumentTitle.ToLower() != "navigation canceled" )
			{

				if ( this._currentElement == 0 )
				{
					if ( this.AutomaticWebRequestReadyForExecution != null )
						this.AutomaticWebRequestReadyForExecution( sender, e );
				}
				else if ( this._currentElement > 0 )
				{
					if ( this.AutomaticWebRequestReadyForNextStep != null )
						this.AutomaticWebRequestReadyForNextStep( sender, e );
				}
			}
		}

		public void SetAutomationElement( AutomationCases AutomationCases )
		{
			this.AutomationCases = AutomationCases;
		}

		public void ExecuteNextStep()
		{

			if ( this._automationElements == null )
			{
				return;
			}

			if ( this.AutomationCases == null )
			{
				throw new InvalidProgramException( "AutomationCases is null. Invalid program situation" );
			}

			if ( this._automationElements != null && this._automationElements.Count <= this._currentElement )
			{
				if ( this.AutomaticWebRequestCompleted != null )
				{
					this.AutomaticWebRequestCompleted( this, new AutomaticWebRequestCompletedEventArgs() { Message = "", Success = true } );
					this.RequestCompleted = true;
					return;
				}
			}

			if ( this._automationElements != null && this._automationElements.Count > this._currentElement )
			{
				using ( AutomationElement ae = this._automationElements[ this._currentElement ] )
				{
					foreach ( AutomationElementAttribute attribute in ae.Attributes )
					{
						this.WebBrowser.Document.GetElementById( ae.ElementID ).SetAttribute( attribute.Key, attribute.Value );
					}
					if ( ae.ElementEventType == AutomationElementEventType.RaiseDocumentEvent )
					{
						this._currentElement++;
						this.WebBrowser.Document.All[ ae.ElementID ].RaiseEvent( ae.ElementEvent );
					}
					else if ( ae.ElementEventType == AutomationElementEventType.InvokeElementMember )
					{
						this._currentElement++;
						this.WebBrowser.Document.GetElementById( ae.ElementID ).InvokeMember( ae.ElementEvent );
					}
					else if ( ae.ElementEventType == AutomationElementEventType.None )
					{
						this._currentElement++;
						if ( this.AutomaticWebRequestReadyForNextStep != null )
							this.AutomaticWebRequestReadyForNextStep( this.WebBrowser, this._e );
					}
				}
			}

			if ( this._automationElements == null )
			{
				return;
			}

			if ( this._automationElements.Count <= this._currentElement )
				this._automationElements = this.GetCurrentElementSet();

		}

		private void SetAutomationElement()
		{
			//this.AutomationElements = new AutomationElements();
			XmlDocument document = new XmlDocument();
			document.Load( this.WuiaXmlFile );
			XmlNodeList cases = document.GetElementsByTagName( "cases" );
			this._url = cases[ 0 ].Attributes[ "wuiauri" ].Value;
			this.AutomationCases = new AutomationCases();

			AutomationCase oCase = null;
			AutomationStep oStep = null;
			AutomationElement oElement = null;
			foreach ( XmlNode acase in cases[ 0 ].ChildNodes )
			{
				oCase = new AutomationCase();
				oCase.AutomationSteps = new AutomationSteps();
				foreach ( XmlNode steps in acase.ChildNodes )
				{
					oStep = new AutomationStep();
					oStep.AutomationElements = new AutomationElements();
					foreach ( XmlNode step in steps.ChildNodes )
					{
						oElement = new AutomationElement();
						oElement.ElementEvent = step[ "elementevent" ].InnerText;
						oElement.ElementEventStatus = bool.Parse( step[ "elementeventstatus" ].InnerText );
						oElement.ElementEventType = ( AutomationElementEventType ) Enum.Parse( typeof( AutomationElementEventType ), step[ "elementeventtype" ].InnerText );
						oElement.ElementID = step[ "elementid" ].InnerText;
						AutomationElementAttribute attribute = null;
						foreach ( XmlNode attr in step[ "attributes" ].ChildNodes )
						{
							attribute = new AutomationElementAttribute();
							attribute.Key = attr[ "key" ].InnerText;
							attribute.Value = attr[ "value" ].InnerText;
							oElement.Attributes.Add( attribute );
						}
						oStep.AutomationElements.Add( oElement );
					}
					if ( this._automationElements == null )
					{
						this._automationElements = oStep.AutomationElements;
					}
					oCase.AutomationSteps.Add( oStep );
				}
				this.AutomationCases.Add( oCase );
			}
		}

		private AutomationElements GetCurrentElementSet()
		{
			if ( this.AutomationCases == null )
			{
				throw new InvalidProgramException( "AutomationCases are null. Invalid program situation" );
			}

			if ( !( this.AutomationCases != null && this.AutomationCases.Count > 0 && this.AutomationCases[ 0 ].AutomationSteps != null && this.AutomationCases[ 0 ].AutomationSteps.Count > 0
				&& this.AutomationCases[ 0 ].AutomationSteps[ 0 ].AutomationElements != null && this.AutomationCases[ 0 ].AutomationSteps[ 0 ].AutomationElements.Count > 0 ) )
			{
				throw new InvalidProgramException( "Invalid program situation. Either of case/step/element is null or empty." );
			}

			if ( this.AutomationCases[ this._currentCase ].AutomationSteps[ this._currentStep ].AutomationElements.Count > this._currentElement )
			{
				if ( this.AutomaticWebRequestCaseCompleted != null )
				{
					AutomaticWebRequestCaseCompletedEventArgs e = new AutomaticWebRequestCaseCompletedEventArgs();
					e.AutomationCase = this.AutomationCases[ this._currentCase ];
					this.AutomaticWebRequestCaseCompleted( this, e );
				}

				this._currentElement++;
				if ( this.AutomationCases[ this._currentCase ].AutomationSteps.Count > this._currentStep )
				{
					if ( this.AutomaticWebRequestStepCompleted != null )
					{
						AutomaticWebRequestStepCompletedEventArgs e = new AutomaticWebRequestStepCompletedEventArgs();
						e.AutomationStep = this.AutomationCases[ this._currentCase ].AutomationSteps[ this._currentStep ];
						this.AutomaticWebRequestStepCompleted( this, e );
					}
					this._currentStep++;
					//if ( this.AutomationCases.Count > this._currentCase )
					//{
					//	this._currentCase++;
					//}
				}
			}
			else
			{
				this._currentStep++;
			}

			if ( this.AutomationCases[ this._currentCase ].AutomationSteps.Count > this._currentStep )
			{
				return this.AutomationCases[ this._currentCase ].AutomationSteps[ this._currentStep ].AutomationElements;
			}
			else
			{
				this._currentCase++;
			}

			if ( this.AutomationCases.Count > this._currentCase )
			{
				return this.AutomationCases[ this._currentCase ].AutomationSteps[ this._currentStep ].AutomationElements;
			}
			else
			{
				this.AutomaticWebRequestCompleted( this.WebBrowser, new AutomaticWebRequestCompletedEventArgs() { Message = "", Success = true } );
			}

			//if ( this.AutomationCases[ this._currentCase ].AutomationSteps == null )
			//	throw new InvalidProgramException( "AutomationCases are null. Invalid program situation" );
			//else if ( this.AutomationCases[ this._currentCase ].AutomationSteps.Count <= this._currentStep )
			//	throw new InvalidProgramException( "AutomationCases are null. Invalid program situation" );

			return null;
		}

		public void StartExecution()
		{
			this.WebBrowser.Url = new Uri( this._url );
			this.WebBrowser.Refresh();
		}

	}

	internal delegate void WebBrowserDocumentCompleted( object sender, WebBrowserDocumentCompletedEventArgs e );
	public delegate void AutomaticWebRequestReadyForExecution( object sender, WebBrowserDocumentCompletedEventArgs e );
	public delegate void AutomaticWebRequestReadyForNextStep( object sender, WebBrowserDocumentCompletedEventArgs e );
	public delegate void AutomaticWebRequestStepCompleted( object sender, AutomaticWebRequestStepCompletedEventArgs e );
	public delegate void AutomaticWebRequestCaseCompleted( object sender, AutomaticWebRequestCaseCompletedEventArgs e );
	public delegate void AutomaticWebRequestCompleted( object sender, AutomaticWebRequestCompletedEventArgs e );

	public class AutomaticWebRequestCompletedEventArgs : EventArgs
	{
		public string Message { get; set; }
		public bool Success { get; set; }
	}

	public class AutomaticWebRequestStepCompletedEventArgs : EventArgs
	{
		public AutomationStep AutomationStep { get; set; }
		public string Message { get; set; }
		public bool Success { get; set; }
	}

	public class AutomaticWebRequestCaseCompletedEventArgs : EventArgs
	{
		public AutomationCase AutomationCase { get; set; }
		public string Message { get; set; }
		public bool Success { get; set; }
	}

}
